core: Create a directory for each transaction
authorColin Walters <walters@verbum.org>
Sun, 15 Jan 2012 15:47:05 +0000 (10:47 -0500)
committerColin Walters <walters@verbum.org>
Sun, 15 Jan 2012 16:03:01 +0000 (11:03 -0500)
This helps ensure that we can more easily identify stale tempfiles
left over if we crash in the middle of a transaction.

src/libostree/ostree-repo.c

index 06fe37f222695e51c31a6fa28caca8499fc125a6..9def9e56000a169b1caef79142a13a177a2781e7 100644 (file)
@@ -31,6 +31,9 @@
 #include <gio/gunixoutputstream.h>
 #include <gio/gunixinputstream.h>
 
+#include <stdio.h>
+#include <stdlib.h>
+
 #ifdef HAVE_LIBARCHIVE
 #include <archive.h>
 #include <archive_entry.h>
@@ -60,6 +63,7 @@ struct _OstreeRepoPrivate {
 
   gboolean inited;
   gboolean in_transaction;
+  GFile *transaction_dir;
 
   GKeyFile *config;
   OstreeRepoMode mode;
@@ -79,6 +83,7 @@ ostree_repo_finalize (GObject *object)
   g_clear_object (&priv->remote_heads_dir);
   g_clear_object (&priv->objects_dir);
   g_clear_object (&priv->config_file);
+  g_clear_object (&priv->transaction_dir);
   g_hash_table_destroy (priv->pending_transaction_tmpfiles);
   if (priv->config)
     g_key_file_free (priv->config);
@@ -778,7 +783,7 @@ impl_stage_archive_file_object_from_raw (OstreeRepo         *self,
                                              g_variant_get_size (serialized),
                                              NULL);
 
-  if (!ostree_create_temp_file_from_input (priv->tmp_dir,
+  if (!ostree_create_temp_file_from_input (priv->transaction_dir,
                                            "archive-tmp-", NULL,
                                            NULL, NULL, mem,
                                            OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
@@ -788,7 +793,7 @@ impl_stage_archive_file_object_from_raw (OstreeRepo         *self,
     goto out;
 
   temp_info = dup_file_info_owned_by_me (file_info);
-  if (!ostree_create_temp_file_from_input (priv->tmp_dir,
+  if (!ostree_create_temp_file_from_input (priv->transaction_dir,
                                            "archive-tmp-", NULL,
                                            temp_info, NULL, input,
                                            OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
@@ -904,7 +909,7 @@ stage_object_impl (OstreeRepo         *self,
         }
       else 
         {
-          if (!ostree_create_temp_file_from_input (priv->tmp_dir,
+          if (!ostree_create_temp_file_from_input (priv->transaction_dir,
                                                    "store-tmp-", NULL,
                                                    file_info, xattrs, input,
                                                    objtype,
@@ -989,13 +994,33 @@ ostree_repo_prepare_transaction (OstreeRepo     *self,
                                  GCancellable   *cancellable,
                                  GError        **error)
 {
+  gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  GString *tmpdir = NULL;
+
+  tmpdir = g_string_new ("");
   
   g_return_val_if_fail (priv->in_transaction == FALSE, FALSE);
 
   priv->in_transaction = TRUE;
+  g_clear_object (&priv->transaction_dir);
+  g_string_append (tmpdir, ot_gfile_get_path_cached (priv->tmp_dir));
+  g_string_append_c (tmpdir, '/');
+  g_string_append_printf (tmpdir, "trans-%lu.XXXXXX",
+                          (gulong)getpid ());
+  if (!mkdtemp (tmpdir->str))
+    {
+      ot_util_set_error_from_errno (error, errno);
+      goto out;
+    }
 
-  return TRUE;
+  priv->transaction_dir = ot_gfile_new_for_path (tmpdir->str);
+
+  ret = TRUE;
+ out:
+  if (tmpdir)
+    g_string_free (tmpdir, TRUE);
+  return ret;
 }
 
 gboolean      
@@ -1012,8 +1037,6 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
 
   g_return_val_if_fail (priv->in_transaction == TRUE, FALSE);
 
-  priv->in_transaction = FALSE;
-
   g_hash_table_iter_init (&iter, priv->pending_transaction_tmpfiles);
   while (g_hash_table_iter_next (&iter, &key, &value))
     {
@@ -1030,7 +1053,7 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
       objtype = ostree_object_type_from_string (type_str + 1);
 
       g_clear_object (&f);
-      f = g_file_get_child (priv->tmp_dir, filename);
+      f = g_file_get_child (priv->transaction_dir, filename);
       
       if (!commit_staged_file (self, f, checksum, objtype, cancellable, error))
         goto out;
@@ -1038,6 +1061,10 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
 
   ret = TRUE;
  out:
+  (void) rmdir (ot_gfile_get_path_cached (priv->transaction_dir));
+  priv->in_transaction = FALSE;
+  g_clear_object (&priv->transaction_dir);
+
   g_free (checksum);
   g_hash_table_remove_all (priv->pending_transaction_tmpfiles);
   g_clear_object (&f);
@@ -1057,19 +1084,21 @@ ostree_repo_abort_transaction (OstreeRepo     *self,
 
   g_return_val_if_fail (priv->in_transaction == TRUE, FALSE);
 
-  priv->in_transaction = FALSE;
-
   g_hash_table_iter_init (&iter, priv->pending_transaction_tmpfiles);
   while (g_hash_table_iter_next (&iter, &key, &value))
     {
       const char *filename = value;
 
       g_clear_object (&f);
-      f = g_file_get_child (priv->tmp_dir, filename);
+      f = g_file_get_child (priv->transaction_dir, filename);
       
       (void) unlink (ot_gfile_get_path_cached (f));
     }
 
+  priv->in_transaction = FALSE;
+  (void) rmdir (ot_gfile_get_path_cached (priv->transaction_dir));
+  g_clear_object (&priv->transaction_dir);
+
   ret = TRUE;
   g_hash_table_remove_all (priv->pending_transaction_tmpfiles);
   g_clear_object (&f);
@@ -1128,7 +1157,7 @@ ostree_repo_load_variant (OstreeRepo  *self,
   pending_key = create_checksum_and_objtype (sha256, expected_type);
   if ((pending_tmpfile = g_hash_table_lookup (priv->pending_transaction_tmpfiles, pending_key)) != NULL)
     {
-      tmpfile = g_file_get_child (priv->tmp_dir, pending_tmpfile);
+      tmpfile = g_file_get_child (priv->transaction_dir, pending_tmpfile);
       if (!ostree_map_metadata_file (tmpfile, expected_type, &ret_variant, error))
         goto out;
     }